```vue
<script setup>
import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';
import AddInfoDialog from '@/components/dialog/AddInfoDialog.vue';
import { getCourses, getScheduleList, addSchedule, updateSchedule, deleteSchedule } from '@/api/manager.js';

const route = useRoute();
const classId = ref(Number(route.params.id));
const scheduleData = ref([]);
const selectedRows = ref([]);
const showAddDialog = ref(false);
const showEditDialog = ref(false);
const editingCourse = ref(null);
const courses = ref([]);
const value1 = ref([]); // 日期范围 [startDate, endDate]
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
const loading = ref(false);

// 表单数据
const formData = ref({
  topic: '',
  courseId: '',
  mode: '',
  date: '',
  time: '',
  instructor: '默认讲师',
  assistant: '',
  classroom: '',
  duration: '',
});

// 获取课次列表
async function fetchSchedule() {
  loading.value = true;
  try {
    const params = {
      classId: classId.value,
      current: currentPage.value,
      size: pageSize.value,
      startDate: value1.value[0] ? new Date(value1.value[0]).toISOString().split('T')[0] : undefined,
      endDate: value1.value[1] ? new Date(value1.value[1]).toISOString().split('T')[0] : undefined,
    };
    const res = await getScheduleList(params);
    if (res.code === 200) {
      scheduleData.value = Array.isArray(res.data.records) ? res.data.records : [];
      total.value = Number(res.data.total) || 0;
    } else {
      ElMessage.error(res.message || '获取排课表失败');
    }
  } catch (error) {
    console.error('获取排课表失败:', error);
    ElMessage.error('获取排课表失败，请稍后重试');
    scheduleData.value = [];
    total.value = 0;
  } finally {
    loading.value = false;
  }
}

// 获取课程列表
async function fetchCourses() {
  try {
    const res = await getCourses();
    if (res.code === 200) {
      courses.value = Array.isArray(res.data) ? res.data : [];
    } else {
      ElMessage.error(res.message || '获取课程列表失败');
    }
  } catch (error) {
    console.error('获取课程列表失败:', error);
    ElMessage.error('获取课程列表失败，请稍后重试');
  }
}

const handleAddCourse = async () => {
  if (!formData.value.topic || !formData.value.courseId || !formData.value.mode ||
      !formData.value.date || !formData.value.time || !formData.value.instructor ||
      !formData.value.classroom || !formData.value.duration) {
    ElMessage.error('请填写所有必填字段');
    return;
  }
  const duration = parseFloat(formData.value.duration);
  if (isNaN(duration) || duration <= 0) {
    ElMessage.error('课时数必须是大于0的数字');
    return;
  }
  const courseId = formData.value.courseId.toString(); // 使用字符串
  const classIdNum = Number(classId.value);
  if (!courseId || isNaN(classIdNum)) {
    ElMessage.error('课程ID或班级ID无效');
    return;
  }
  const validCourse = courses.value.find(course => course.id.toString() === courseId);
  if (!validCourse) {
    ElMessage.error('所选课程ID无效，请重新选择');
    return;
  }
  const timeRegex = /^\d{1,2}:\d{2}\s*-\s*\d{1,2}:\d{2}$/;
  if (!timeRegex.test(formData.value.time)) {
    ElMessage.error('上课时段格式不正确，请使用类似 09:00-11:00 的格式');
    return;
  }
  let dateTime;
  try {
    const [startTime] = formData.value.time.split('-');
    const [hours, minutes] = startTime.trim().split(':');
    const formattedHours = hours.padStart(2, '0');
    dateTime = `${formData.value.date}T${formattedHours}:${minutes}:00`;
  } catch (error) {
    ElMessage.error('上课时段格式不正确，请使用类似 09:00-11:00 的格式');
    return;
  }
  try {
    const payload = {
      topic: formData.value.topic,
      courseId: courseId, // 发送字符串
      classId: classIdNum,
      mode: formData.value.mode,
      date: dateTime,
      time: formData.value.time,
      instructor: formData.value.instructor,
      classroom: formData.value.classroom,
      duration: duration,
      assistant: formData.value.assistant || null,
    };
    console.log('发送的 payload:', payload, 'Timestamp:', Date.now());
    const res = await addSchedule(payload);
    if (res.code === 200) {
      ElMessage.success('课程添加成功');
      showAddDialog.value = false;
      resetForm();
      fetchSchedule();
    } else {
      ElMessage.error(res.message || '添加课次失败');
    }
  } catch (error) {
    console.error('添加课次失败:', error.response?.data || error.message);
    ElMessage.error(`添加课次失败: ${error.response?.data?.message || error.message || '请求错误'}`);
  }
};
// 处理修改课次名称
const handleEditCourse = async () => {
  if (!editingCourse.value?.topic) {
    ElMessage.error('课次名称不能为空');
    return;
  }
  try {
    const res = await updateSchedule(editingCourse.value.id, { topic: editingCourse.value.topic });
    if (res.code === 200) {
      scheduleData.value = scheduleData.value.map(item =>
          item.id === editingCourse.value.id ? { ...item, topic: res.data.topic } : item
      );
      ElMessage.success('课次名称修改成功');
      showEditDialog.value = false;
      editingCourse.value = null;
    } else {
      ElMessage.error(res.message || '修改课次失败');
    }
  } catch (error) {
    console.error('修改课次失败:', error);
    ElMessage.error('修改课次失败，请稍后重试');
  }
};

// 处理删除选中的行
async function handleDelete() {
  if (selectedRows.value.length === 0) {
    ElMessage.warning('请先选择要删除的课程');
    return;
  }
  try {
    for (const row of selectedRows.value) {
      await deleteSchedule(row.id);
    }
    ElMessage.success('删除成功');
    selectedRows.value = [];
    fetchSchedule();
  } catch (error) {
    console.error('删除课次失败:', error);
    ElMessage.error('删除课次失败，请稍后重试');
  }
}

// 重置表单
const resetForm = () => {
  formData.value = {
    topic: '',
    courseId: '',
    mode: '',
    date: '',
    time: '',
    instructor: '默认讲师',
    assistant: '',
    classroom: '',
    duration: '',
  };
};

// 打开添加课次对话框
const scheduleClass = () => {
  showAddDialog.value = true;
};

// 打开修改课次名称对话框
const openEditDialog = (row) => {
  editingCourse.value = { id: row.id, topic: row.topic };
  showEditDialog.value = true;
};

// 处理备课
const prepareCourse = (row) => {
  ElMessage.info(`正在为课程 ${row.topic} 准备课件...`);
};

// 处理表格选择变化
const handleSelectionChange = (rows) => {
  selectedRows.value = rows;
};

// 处理搜索
const handleSearch = () => {
  currentPage.value = 1;
  fetchSchedule();
};

// 处理分页
const handleCurrentChange = (newPage) => {
  currentPage.value = newPage;
  fetchSchedule();
};

// 处理每页大小变化
const handleSizeChange = (newSize) => {
  pageSize.value = newSize;
  currentPage.value = 1;
  fetchSchedule();
};

onMounted(() => {
  if (classId.value && !isNaN(classId.value)) {
    fetchSchedule();
    fetchCourses();
  } else {
    ElMessage.error('无效的班级 ID');
  }
});
</script>

<template>
  <div class="demo-date-picker container mx-auto p-6 bg-gray-50 rounded-lg">
    <div class="flex items-center justify-between mb-6">
      <div class="flex items-center space-x-4">
        <div class="block">
          <el-date-picker
              v-model="value1"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              class="w-full"
              size="default"
              @change="handleSearch"
          />
        </div>
        <el-button type="primary" size="default" class="px-6" @click="handleSearch" :loading="loading">搜索</el-button>
      </div>
      <div class="flex items-center space-x-3">
        <el-button type="success" size="default" @click="scheduleClass" class="px-6">排课</el-button>
        <el-button type="danger" size="default" @click="handleDelete" class="px-6">删除</el-button>
      </div>
    </div>
    <el-table
        :data="scheduleData"
        stripe
        style="width: 100%"
        class="rounded-lg shadow-sm"
        v-loading="loading"
        @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" />
      <el-table-column prop="date" label="上课时间" width="180" sortable>
        <template #default="{ row }">
          {{ row.date }} {{ row.time }}
        </template>
      </el-table-column>
      <el-table-column prop="topic" label="课次名称" width="150" />
      <el-table-column prop="courseName" label="所属课程" width="150" />
      <el-table-column prop="instructor" label="讲师" width="120" />
      <el-table-column prop="assistant" label="教务" width="120" />
      <el-table-column prop="classroom" label="教室" width="120" />
      <el-table-column prop="duration" label="课耗(小时)" width="120" />
      <el-table-column label="实到/应到" width="120">
        <template #default="{ row }">
          {{ row.attendanceActual || 0 }}/{{ row.attendanceExpected || 0 }}
        </template>
      </el-table-column>
      <el-table-column prop="mode" label="上课模式" width="100">
        <template #default="{ row }">
          {{ row.mode === 'online' ? '线上' : '线下' }}
        </template>
      </el-table-column>
      <el-table-column prop="status" label="课次状态" width="100" />
      <el-table-column label="操作" width="200">
        <template #default="{ row }">
          <el-button type="primary" size="small" @click="prepareCourse(row)">备课</el-button>
          <el-button type="warning" size="small" @click="openEditDialog(row)">修改</el-button>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
        layout="prev, pager, next, sizes"
        :current-page="currentPage"
        :page-size="pageSize"
        :total="total"
        @current-change="handleCurrentChange"
        @size-change="handleSizeChange"
        class="page mt-4"
    />
    <!-- 添加课程对话框 -->
    <add-info-dialog v-model:visible="showAddDialog" @submit="handleAddCourse">
      <template #title>
        <span class="text-2xl font-bold text-gray-800">添加新课程</span>
      </template>
      <template #content>
        <div class="form-group space-y-6">
          <div class="grid grid-cols-2 gap-6">
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">课次名称 <span class="text-red-500">*</span></span>
              <input
                  type="text"
                  v-model="formData.topic"
                  placeholder="请输入课次名称"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                  required
              />
            </label>
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">所属课程 <span class="text-red-500">*</span></span>
              <select
                  v-model="formData.courseId"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                  required
              >
                <option value="" disabled>请选择课程</option>
                <option v-for="course in courses" :key="course.id" :value="course.id">{{ course.name }}</option>
              </select>
            </label>
          </div>
          <div class="grid grid-cols-2 gap-6">
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">上课模式 <span class="text-red-500">*</span></span>
              <select
                  v-model="formData.mode"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                  required
              >
                <option value="" disabled>请选择上课模式</option>
                <option value="online">线上</option>
                <option value="offline">线下</option>
              </select>
            </label>
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">上课日期 <span class="text-red-500">*</span></span>
              <input
                  type="date"
                  v-model="formData.date"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                  required
              />
            </label>
          </div>
          <div class="grid grid-cols-2 gap-6">
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">上课时段 <span class="text-red-500">*</span></span>
              <input
                  type="text"
                  v-model="formData.time"
                  placeholder="例如: 09:00-11:00"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                  required
              />
            </label>
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">讲师 <span class="text-red-500">*</span></span>
              <input
                  type="text"
                  v-model="formData.instructor"
                  placeholder="请输入讲师姓名"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                  required
              />
            </label>
          </div>
          <div class="grid grid-cols-2 gap-6">
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">教务</span>
              <input
                  type="text"
                  v-model="formData.assistant"
                  placeholder="请输入教务姓名（可选）"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
              />
            </label>
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">上课教室 <span class="text-red-500">*</span></span>
              <input
                  type="text"
                  v-model="formData.classroom"
                  placeholder="请输入教室名称"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                  required
              />
            </label>
          </div>
          <div class="grid grid-cols-2 gap-6">
            <label class="flex flex-col">
              <span class="text-sm font-medium text-gray-700 mb-2">单次课耗（小时） <span class="text-red-500">*</span></span>
              <input
                  type="number"
                  v-model="formData.duration"
                  placeholder="请输入课时数"
                  min="0.5"
                  step="0.5"
                  class="border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                  required
              />
            </label>
          </div>
        </div>
      </template>
    </add-info-dialog>
    <!-- 修改课次名称对话框 -->
    <add-info-dialog v-model:visible="showEditDialog" @submit="handleEditCourse">
      <template #title>
        <span class="text-2xl font-bold text-gray-800">修改课次名称</span>
      </template>
      <template #content>
        <div class="form-group">
          <label class="flex flex-col">
            <span class="text-sm font-medium text-gray-700 mb-2">课次名称 <span class="text-red-500">*</span></span>
            <el-input
                v-model="editingCourse.topic"
                placeholder="请输入课次名称"
                class="border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
                required
            />
          </label>
        </div>
      </template>
    </add-info-dialog>
  </div>
</template>

<style scoped>
@import 'https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css';

.el-table :deep(.el-table__row--striped) {
  background-color: #f9fafb;
}

.el-table {
  @apply border border-gray-200 rounded-lg;
}

.el-table th {
  @apply bg-gray-100 text-gray-700 font-semibold;
}

input, select, .el-input {
  @apply w-full;
}

input:focus, select:focus, .el-input:focus {
  @apply outline-none;
}

.el-button--small {
  @apply px-3 py-1 text-sm;
}

.page {
  @apply flex justify-end mt-4;
}
</style>
```